﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;
using Generator.Helpers;
using System.Security.AccessControl;

namespace Generator.Service
{
    /// <summary>
    /// Cette classe représente le générateur de VSTemplate
    /// </summary>
    public class VSProjectTemplateGenerator : VSTemplateGenerator
    {
        private string shortprojectFilename;

        private List<string> projectIncludeCollection;

        public int ProjectId { get; set; }

        public string ProjectGuid { get; private set; }

        public string ProjectFilename { get; set; }

        public string OutputProjectFile { get; private set; }

        public string ProjectName { get; private set; }

        #region Constructor

        /// <summary>
        /// Constructeur par défaut
        /// </summary>
        public VSProjectTemplateGenerator()
            : base()
        {
            this.projectIncludeCollection = new List<string>();
        }

        #endregion

        #region Abstract Execute Method

        /// <summary>
        /// Cette méthode permet de générer le template VS dans le répertoire Output
        /// </summary>
        /// <param name="sourceFolder">Répertoire Source pour créer le VSTemplate</param>
        /// <param name="outputFolder">sorite du fichier</param>
        public override void Execute(string sourceFolder, string outputFolder)
        {
            this.ProjectGuid = string.Empty;
            this.SourceFolder = sourceFolder;
            this.OutputFolder = outputFolder;
            this.Content = this.vsTemplateHelper.ReadDocument(".\\Assets\\" + VSTemplateHelper.PROJECT_TEMPLATE_NAME);

            // Nom court du fichier projet
            this.shortprojectFilename = this.fileHelper.ShortFilename(this.ProjectFilename);
            var iExtension = this.shortprojectFilename.LastIndexOf('.');
            if (iExtension > 0)
            {
                this.ProjectName = this.shortprojectFilename.Remove(iExtension, this.shortprojectFilename.Length - iExtension);
            }

            // Recherche des includes issus du .csproj
            this.projectIncludeCollection.AddRange(this.vsTemplateHelper.GetProjectInclude(this.ProjectFilename));

            // Copie du fichier .csproj
            this.OutputProjectFile = this.OutputFolder + this.shortprojectFilename;
            File.Copy(this.ProjectFilename, this.OutputProjectFile, true);

            // Création de l'élément Projet
            var projectElement = this.vsTemplateHelper.CreateProjectElement(shortprojectFilename);
            this.Content.Root.Element(VSTemplateHelper.TEMPLATE_CONTENT).Add(projectElement);

            // Traitement du fichier Projet
            var projectDocument = this.vsTemplateHelper.ReadDocument(this.ProjectFilename);
            var projectIdElement = projectDocument.Root.Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "PropertyGroup").Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "ProjectGuid").FirstOrDefault();
            if (projectIdElement != null)
            {
                this.ProjectGuid = projectIdElement.Value;
                projectIdElement.Value = "{" + string.Format(TextReplaceHelper.GUID, this.ProjectId) + "}";
            }

            // Remplacement RootNamespace, AssemblyName, SilverlightAppEntry, XapFilename,TestPageFileName
            var rootNamespaceElement = projectDocument.Root.Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "PropertyGroup").Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "RootNamespace").FirstOrDefault();
            if (rootNamespaceElement != null)
            {
                rootNamespaceElement.Value = this.textReplaceHelper.ReplaceNamespace(rootNamespaceElement.Value);
            }
            var assemblyNameElement = projectDocument.Root.Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "PropertyGroup").Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "AssemblyName").FirstOrDefault();
            if (assemblyNameElement != null)
            {
                assemblyNameElement.Value = this.textReplaceHelper.ReplaceNamespace(assemblyNameElement.Value);
            }
            var silverlightAppEntryElement = projectDocument.Root.Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "PropertyGroup").Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "SilverlightAppEntry").FirstOrDefault();
            if (silverlightAppEntryElement != null)
            {
                silverlightAppEntryElement.Value = this.textReplaceHelper.ReplaceNamespace(silverlightAppEntryElement.Value);
            }
            var xapFilenameElement = projectDocument.Root.Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "PropertyGroup").Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "XapFilename").FirstOrDefault();
            if (xapFilenameElement != null)
            {
                xapFilenameElement.Value = this.textReplaceHelper.ReplaceNamespace(xapFilenameElement.Value);
            }
            var testPageFileNameElement = projectDocument.Root.Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "PropertyGroup").Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "TestPageFileName").FirstOrDefault();
            if (testPageFileNameElement != null)
            {
                testPageFileNameElement.Value = this.textReplaceHelper.ReplaceNamespace(testPageFileNameElement.Value);
            }

            // Remplacement de l'element SilverlightApplicationList
            var silverlightApplicationList = projectDocument.Root.Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "PropertyGroup").Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "SilverlightApplicationList").FirstOrDefault();
            if (silverlightApplicationList != null)
            {
                silverlightApplicationList.Value = this.textReplaceHelper.ReplaceNamespace(silverlightApplicationList.Value);

                // Remplacement du Content Xap dans le ficheir .csproj (website)
                var contentXapElements = projectDocument.Root.Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "ItemGroup").Elements(VSTemplateHelper.MSBUILD_NAMESPACE + "Content");
                foreach (var item in contentXapElements)
                {
                    item.Attribute("Include").Value = this.textReplaceHelper.ReplaceNamespace(item.Attribute("Include").Value);
                }
            }

            var outputFile = outputFolder + this.shortprojectFilename;
            if (File.Exists(outputFile) &&
                (File.GetAttributes(outputFile) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
            {
                //File.SetAccessControl(outputFolder + this.shortprojectFilename, new FileSecurity(outputFolder + this.shortprojectFilename, AccessControlSections.All));
                FileHelper.RemoveReadOnlyAttribute(outputFile);
                //File.SetAttributes(outputFile, FileAttributes.Normal);
            }

            projectDocument.Save(outputFile);

            // Parse les fichiers
            this.Parse(projectElement, this.SourceFolder, this.OutputFolder);

            // Sauvegarde du vsTemplate Projet
            this.Content.Save(this.OutputFolder + this.shortprojectFilename.Replace(VSTemplateHelper.PROJECT_EXTENSION, VSTemplateHelper.VSTEMPLATE_EXTENSION));
        }

        #endregion

        private void Parse(XElement element, string sourceFolder, string outputFolder)
        {
            var currentElement = element;

            // Ajout dans le fichier de l'element
            // currentElement.Add(this.vsTemplateHelper.CreateProjectItemElement(this.textReplaceHelper.ReplaceNamespace(this.shortprojectFilename), this.shortprojectFilename));

            // Parcours des fichiers
            var fileCollection = Directory.GetFiles(sourceFolder);
            foreach (var item in fileCollection)
            {
                var shortfilename = this.fileHelper.ShortFilename(item);

                // Copie du fichier dans le répertoire cible
                if (this.fileHelper.CheckFilename(shortfilename))
                {
                    var relativeFilename = (sourceFolder.Replace(this.SourceFolder, "") + "\\" + shortfilename).TrimStart('\\');
                    if (this.projectIncludeCollection.Exists(e => e == relativeFilename) && !this.fileHelper.CheckProjectFile(item))
                    {
                        var outputFilename = outputFolder + shortfilename;

                        File.Copy(item, outputFilename, true);

                        this.textReplaceHelper.ReplaceFile(outputFilename,
                            (s => s.Replace(this.ProjectGuid, string.Format(TextReplaceHelper.GUID, this.ProjectId))),
                            (s => this.textReplaceHelper.ReplaceNamespace(s)));

                        // Ajout dans le fichier de l'element
                        currentElement.Add(this.vsTemplateHelper.CreateProjectItemElement(shortfilename, shortfilename));
                    }
                }
                else
                {
                    // Nothing
                }
            }

            // Parcours des répertoires
            var folderCollection = Directory.GetDirectories(sourceFolder);
            foreach (var item in folderCollection)
            {
                var shortFolder = this.fileHelper.ShortFolder(item);
                if (this.fileHelper.CheckFolder(shortFolder))
                {
                    // Traitement sur le repertoire contenant un projet
                    string projectFilename = string.Empty;
                    if (this.fileHelper.CheckContainProjectFile(item, out projectFilename))
                    {
                        // Non implémentable !
                    }
                    else
                    {
                        // Créer le répertoire Output
                        Directory.CreateDirectory(outputFolder + shortFolder);

                        // Créer l'element XML dans le VsTYemplate
                        var newElement = this.vsTemplateHelper.CreateFolderElement(shortFolder);
                        currentElement.Add(newElement);

                        // Parse son contenu
                        this.Parse(newElement, item, outputFolder + shortFolder + "\\");
                    }
                }
                else
                {
                    // Nothing
                }
            }
        }

    }
}
